#ifndef _UTILEX_TIMETHREAD_HPP_
#define _UTILEX_TIMETHREAD_HPP_

#include <crt_util.h>
#include <utilex/cond.hpp>
#include <utilex/notifysem.hpp>

#ifdef __cplusplus

class CTimeThread
{
public:
    CTimeThread()
    {
        m_iExit = 0;
        m_iSec = 0;
        m_iWait = 0;
        m_Thread = INVALID_HANDLE_VALUE;
    }
    virtual ~CTimeThread() { }

    HRESULT SetMilliSecond(int ms)
    {
        m_iSec = ms;
        return S_OK;
    }
    HRESULT PostSingel() { return m_CondPost.Signal(); }

    HRESULT PostBroadcast() { return m_CondPost.Broadcast(); }

public:
    static void time_thread_proc(void* pthis)
    {
        CTimeThread* p = static_cast<CTimeThread*>(pthis);
        if (p) {
            p->PostWorkSem();
            p->Time_Thread_Run_Proc();
        }
    }

    int StartThread()
    {
        int rc = _thread_create(&m_Thread, CTimeThread::time_thread_proc, this);
        rc_error(rc == S_SUCCESS, S_ERROR);
        this->WaitWorkSem();
        return S_SUCCESS;
    }

    int StopThread()
    {
        rc_error(m_Thread != INVALID_HANDLE_VALUE, S_ERROR);

        Exit_Thread();
        PostBroadcast();

        WaitExitSem(30);

        return S_SUCCESS;
    }

    int Jointhread()
    {
        rc_error(m_Thread != INVALID_HANDLE_VALUE, S_ERROR);

        Exit_Thread();
        PostBroadcast();

        // deadlock
        _thread_join(&m_Thread);
        return S_SUCCESS;
    }

protected:
    HRESULT Time_Thread_Run_Proc()
    {
        while (!m_iExit) {
            logi("Time_Thread_Run_Proc stop");
            this->m_CondPost.WaitTime(m_iSec);
            rc_error_break(m_iExit == 0);
            this->Time_Thread_Run();
            logi("Time_Thread_Run_Proc end");
        }
        return S_OK;
    }

private:
    HRESULT PostWorkSem()
    {
        rc_error(m_Thread != INVALID_HANDLE_VALUE, S_ERROR);
        return m_Sem.PostWorkSem();
    }

    HRESULT WaitWorkSem()
    {
        rc_error(m_Thread != INVALID_HANDLE_VALUE, S_ERROR);
        return m_Sem.WaitWorkSem();
    }

    HRESULT PostExitSem()
    {
        rc_error(m_Thread != INVALID_HANDLE_VALUE, S_ERROR);
        return m_Sem.PostExitSem();
    }

    HRESULT WaitExitSem(int sec)
    {
        rc_error(m_Thread != INVALID_HANDLE_VALUE, S_ERROR);
        return m_Sem.WaitExitSem(sec);
    }

    HRESULT Exit_Thread()
    {
        SYNC_OBJ(&m_AutoLock);
        m_iExit = 1;
        return S_OK;
    }

protected:
    std_method(Time_Thread_Run)() PURE;

protected:
    _thread_t m_Thread;
    CAutoLock m_AutoLock;
    CCondHandle m_CondPost;
    CNotifySem m_Sem;

    int m_iWait;
    int m_iExit;
    int m_iSec;
};

#endif

#endif
